package main;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.item.manager.repository.TemplateRepository;
import com.item.manager.serialize.TemplateLoader;
import location.Location;
import weapon.Weapon;
import webserver.WebServer;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import static java.util.Arrays.asList;
import static main.RandomProvider.chooseRandom;

public class World {
    private static final Gson GSON = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC).create();

    private final List<Hero> heroes = new ArrayList<>();
    private final Village village;
    private final List<Location> locations = new ArrayList<>();
    private final TemplateRepository monsterRepo;
    private final TemplateRepository itemRepo;
    private final TemplateRepository trapRepo;
    private final TemplateRepository lootRepo;
    private final TemplateRepository weaponRepo;

    private final AtomicReference<String> heroesJson = new AtomicReference<>();
    private final WebServer server = new WebServer(heroesJson);

    public World() {
        server.start();
        monsterRepo = new TemplateRepository(TemplateLoader.classPath("monster-store.yml"));
        itemRepo = new TemplateRepository(TemplateLoader.classPath(("collectables-store.yml")));
        trapRepo = new TemplateRepository(TemplateLoader.classPath(("traps-store.yml")));
        lootRepo = new TemplateRepository(new TemplateLoader("loot-store.yml"));
        weaponRepo = new TemplateRepository(new TemplateLoader("weapons-store.yml"));

        village = new Village(monsterRepo, itemRepo, trapRepo, lootRepo);
        locations.add(village);
        locations.addAll(village.getExits());
    }

    public void run() {
        while (true) {
            // process all heroes
            heroes.stream().forEach(hero -> hero.process());

            if (RandomProvider.chance(0.01)) {
                emergeHero();
            }

            // process all locations
            locations.stream().forEach(location -> location.process());

            heroesJson.set(GSON.toJson(heroes));

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void emergeHero() {
        Hero hero = new Hero(village, monsterRepo.byName(chooseRandom(monsterRepo.byTag("Hero")).name()));
        heroes.add(hero);
        Logger.log("-----------------------------");
        Logger.log("New hero appears: " + hero);
        Logger.log(" combat\t\t" + hero.getCombat());
        Logger.log(" speed\t\t" + hero.getSpeed());
        Logger.log(" health\t\t" + hero.getHealth());
        Logger.log(" traps\t\t" + hero.getTraps());
        Logger.log(" open locks\t" + hero.getOpenLocks());
        Logger.log(" spot\t\t" + hero.getSpot());
        Logger.log(" evade\t\t" + hero.getEvade());
        Logger.log(" nature\t\t" + hero.getNature());
        Logger.log(" sneak\t\t" + hero.getSneak());

        if (hero.name.startsWith("Fighter")) {
            hero.equipWeapon(new Weapon(weaponRepo.byName(chooseRandom(asList("Long sword", "Axe", "Spear", "Morningstar", "Battlehammer")))));
        } else if (hero.name.startsWith("Rogue")) {
            hero.equipWeapon(new Weapon(weaponRepo.byName(chooseRandom(asList("Dagger", "Short sword", "Short bow", "Crossbow")))));
        } else if (hero.name.startsWith("Ranger")) {
            hero.equipWeapon(new Weapon(weaponRepo.byName(chooseRandom(asList("Club", "Short bow", "Crossbow")))));
        }
    }

    private static int counter = 1;

}
